{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 迭代\n",
    "可迭代对象本质上就是序列观念的一种通用化：如果对象是实际保存的序列或者是可以在迭代工具上下文中（如for循环中）一次产生一个结果的对象，那么就看做是可迭代的。[B1P417]      \n",
    "完整的迭代协议：      \n",
    "- 可迭代对象：迭代的被调对象，其 \\_\\_iter\\_\\_ 方法被 iter 函数所调用。   \n",
    "- 迭代器对象：可迭代对象的返回结果，可迭代对象的返回结果，在迭代过程中实际提供值的对象。它的__next__方法被next运行，并在结束时触发StopIteration异常[B1P421]。如文件迭代器[B1P418]。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 推导"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[('a', 1, '一'), ('b', 2, '二'), ('c', 3, '三')]"
      ]
     },
     "execution_count": 81,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 先介绍 zip 与 map\n",
    "# zip 的输入参数是一个或者多个序列，而他的返回值是将这些序列并排的元素配对得到元组的列表。[B1P407]\n",
    "L1 = ['a', 'b', 'c']\n",
    "L2 = [1, 2, 3]\n",
    "L3 = ['一', '二', '三']\n",
    "list(zip(L1, L2, L3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'a': 1, 'b': 2, 'c': 3}"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 使用 zip 构建字典\n",
    "dict(zip(L1, L2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'a': 1, 'b': 2, 'c': 3}"
      ]
     },
     "execution_count": 83,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 使用推导构建字典\n",
    "{k: v for (k, v) in zip(L1, L2)}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[2, 1, 0, 1]"
      ]
     },
     "execution_count": 84,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# map(function, L1,...,Ln), map 对序列每一个对应位置的元素输入到函数 function 中。\n",
    "# 注意：list(map(None, L1, L2)) 在 2.X 版本中若函数为 None，其功能就类似 zip 中的元素配对，但 3.X 版本中会报错。\n",
    "L3 = [-2, -1, 0, 1] \n",
    "list(map(abs, L3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 :  a\n",
      "1 :  b\n",
      "2 :  c\n"
     ]
    }
   ],
   "source": [
    "# enumerate 同时给出偏移量和元素\n",
    "for (index, value) in enumerate(L1):\n",
    "    print(index,': ', value)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[11, 12, 13]"
      ]
     },
     "execution_count": 86,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 列表推导\n",
    "[x + 10 for x in L2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Honor time with civilization instead of giving civilization time\\n***',\n",
       " '给岁月以文明，而不是给文明以岁月\\n***']"
      ]
     },
     "execution_count": 87,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 文件推导\n",
    "[line + '***' for line in open('file.txt')]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 3]"
      ]
     },
     "execution_count": 88,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 推导上使用 if 筛选\n",
    "[x for x in L2 if x % 2] # 取 L2 中的奇数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['ax', 'ay', 'az', 'bx', 'by', 'bz', 'cx', 'cy', 'cz']"
      ]
     },
     "execution_count": 89,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 让推导包含嵌套循环，允许任意数目的 for 分句，并且每一个 for 分句都带有一个可选的关联的 if 分句\n",
    "[x + y for x in 'abc' for y in 'xyz']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['cx', 'cy']"
      ]
     },
     "execution_count": 90,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[x + y for x in 'abc' if x == 'c' for y in 'xyz' if y in 'xy']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 性能\n",
    "- while 循环比基于迭代器的 for 循环慢的多，因为迭代器在 Python 内部是以 C 语言的速度运行的，而 while 循环则是通过 Python 虚拟机运行 Python 字节码的。[B1P419]\n",
    "- 列表推导比手动 for 循环语句运行得更快（往往速度快一倍），这是因为它们的迭代在解释器内部以 C 语言速度执行的，而不是手动以 Python 代码执行的。尤其对于较大的数据集合，使用列表推导能带来极大的性能优势。[B1P426]\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  map、zip 和可迭代对象\n",
    "与 range 类似，内置函数 map、zip 和 filter 在 Python3.X 中也可以转换成可迭代对象以节约内存空间，而不是一次性在内存中产生一个结果列表。与 range 不同，它们本身都是迭代器——在遍历一次后，它们就用尽了(单遍迭代器)。换句话说，你不能在它们的结果上拥有多个位于不同位置的迭代器（多遍迭代器）。[B1P439]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "0\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "R = range(3)\n",
    "# next(R) # 报错\n",
    "\"\"\"\n",
    "---------------------------------------------------------------------------\n",
    "TypeError                                 Traceback (most recent call last)\n",
    "<ipython-input-67-6e2ac5d5dbd8> in <module>()\n",
    "      1 R = range(3)\n",
    "----> 2 next(R) # 报错\n",
    "\n",
    "TypeError: 'range' object is not an iterator\n",
    "\n",
    "\n",
    "\"\"\"\n",
    "I1 = iter(R)\n",
    "print(next(I1))\n",
    "print(next(I1))\n",
    "I2 = iter(R)\n",
    "print(next(I2))\n",
    "print(next(I1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 字典视图是可迭代对象但本身不是迭代器\n",
    "K = D.keys()   \n",
    "next(K) 会报错"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
